package com.google.code.jmarias.server.tcp;

import com.google.code.jmarias.common.action.SignedAction;
import com.google.code.jmarias.common.ActionSerializer;
import com.google.code.jmarias.common.action.AbstractAction;
import com.google.code.jmarias.common.action.AbstractSignedMessage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Vlakno klienta pripojeneho pres TCP socket, zajistuje jeho komunikaci se serverem.
 *
 * Neni thread safe - neni potreba, neni sdilene mezi vlakny - pro kazde vlakno
 * je vytvorena nova instance.
 *
 * Podoba se HTTP session ve webovem prostredi.
 *
 * @TODO detekovat odpojeni klienta, protoze jinak se vlakno NIKDY neukonci
 *
 * @author Ondrej Michal
 */
public class SocketClient extends Thread {

    private static Log log = LogFactory.getLog(SocketClient.class);

    private BlockingQueue<SignedAction> clientToServerActions;

    private Socket socket;
    private Queue<AbstractSignedMessage> serverToClientActions = new ConcurrentLinkedQueue<AbstractSignedMessage>();
    private ActionSerializer serializer = ActionSerializer.newInstance();

    public SocketClient(Socket socket, BlockingQueue<SignedAction> clientToServerActions) {
        this.socket = socket;
        this.clientToServerActions = clientToServerActions;
    }

    @Override
    public void run() {
        BufferedReader in = null;
        PrintWriter out = null;

        AbstractContactableUser client = new RemoteContactableUser(serverToClientActions);

        //        clientToServerActions.add(new ConnectedClientAction(client));

        try {
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream());

            while (true) {
                try { // Poll every ~1000 ms
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if (in.ready()) {
                    String xml = in.readLine();
                    AbstractAction action = serializer.deserializeAbstractAction(xml);
                    clientToServerActions.add(new SignedAction(client, action));
                }

                // @TODO nemelo by tu byt odeslani vsech cekajicich zprav? (a ne jen jedne)
                AbstractSignedMessage action = serverToClientActions.poll();
                if (action != null) {
                    serializer.serialize(action, out);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) { 
                try {
                    socket.close(); // closes also in and out, see javadoc
                } catch (IOException ex) {
                }
            }
        }

//        clientToServerActions.add(new DisconnectedClientAction());
    }
}
